import * as req from '@/lib/req.coffee'
import {join} from 'path'
import {existsSync} from 'fs'
#import {createReadStream} from 'fs'
import {rm as _rm,mkdir,readFile,writeFile} from 'fs/promises'
import sleep from 'await-sleep'
import {post,upload as _upload,data_form} from './net/user.coffee'
import * as r64 from '@/lib/r64.mjs'
###
import Oss from 'ali-oss'
import {OSS as CONFIG} from './config.coffee'
{API,SPACE} = CONFIG
###


rm = (p)=>
  #console.log p
  #return
  _rm p, {
    recursive: true
    force: true
  }

forever_try = (func)=>
  loop
    try
      await func()
      break
    catch err
      console.trace err
      await sleep 1000
  return

forever_try_fetch = (func)=>
  forever_try =>
    r = await func()
    if not [200,204].includes(r.status)
      throw new Error await r.text()
    r

export upload = (getUserData)=>
  user_dir = getUserData()
  (task)=>
    ###
    refreshSTSToken = =>
      [
        accessKeyId
        accessKeySecret
        stsToken
      ] = await req.json(API+prefix)
      {
        accessKeyId
        accessKeySecret
        stsToken
      }

    oss = new Oss {
      refreshSTSToken
      refreshSTSTokenInterval:3500000
      ... (await refreshSTSToken())
      ... SPACE
    }
    ###
    ing = new Set()

    runing = false

    oss = host = end_resolve = end = prefix = local_dir = task_id = undefined

    end_promise = new Promise (resolve)=>
      end_resolve = resolve
      return


    get_task_id = do =>
      {id:task_id, host} = oss = await post('upload/start.do?mode=oss')
      chunk_ = 'chunk_'
      oss = {
        OSSAccessKeyId:oss.accessKeyId
        policy:oss.policy
        key:oss.dir+chunk_
        signature:oss.signature
        name:chunk_
      }

      {uid} = localStorage

      path_li = [uid, task_id]
      local_dir = join await user_dir,'upload',task,...path_li

      prefix = path_li.join('/')

      prefix+='/'
      await mkdir local_dir, recursive:true
      return

    put = =>
      while ing.size
        for name from ing.values()
          fp = join local_dir,name
          if existsSync fp
            file = await readFile fp
            data = {
              ...oss
              file: new File(
                [
                  file
                ]
                'blob'
              )
            }
            chunkNum = parseInt(r64.decode name)
            url_name = (
              chunkNum+''
            ).padStart(4,0)
            data.name+=url_name
            data.key+=url_name
            await forever_try_fetch =>
              fetch(
                host
                data_form data
              )
              ###
              await oss.putStream(
                url
                createReadStream fp
                mime: 'video/webm'
              )
              ###
            await rm fp
            await forever_try_fetch =>
              _upload(
                'upload/update'
                {
                  id:task_id
                  chunkNum
                  size:file.length
                }
              )
          ing.delete name
      return

    [
      (id, data)=> # 上传区块
        await get_task_id
        id = r64.encode id
        fp = join local_dir, id
        await writeFile(
          fp
          new DataView await data.arrayBuffer()
        )
        ing.add id
        if runing
          return
        runing = put().then =>
          runing = false
          if end
            end_resolve()
          return

        return
      => # 完成上传
        end = true
        await end_promise
        await Promise.allSettled [
          rm local_dir
          _upload('upload/complete',id:task_id)
        ]
        return task_id
      => # 结束上传
        await Promise.allSettled [
          rm local_dir
          _upload('upload/cancel',id:task_id)
        ]
        return

    ]
  ###
  [
    accessKeyId
    accessKeySecret
    stsToken
  ] = await req.json(
    'https://xxx.xxx'
  )
  # https://www.jianshu.com/p/eaba1f2afa70?spm=a2c6h.13066369.0.0.4f1f31ceBd3o5K
  await o.put url,data
  #await data.arrayBuffer()
  ###
